package com.botarena.client.ui;

import java.util.ArrayList;
import java.util.List;

import com.botarena.shared.BattleTurn;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;

public class GomokuVisualizer extends VerticalPanel {

	private static final String TO_END_BUTTON = "end >>>";
	private static final String FORWARD_BUTTON = "next >>";
	private static final String PLAY_BUTTON = "play >";
	private static final String PAUSE_BUTTON = "|stop|";
	private static final String BACKWARD_BUTTON = "<< prev";
	private static final String RESET_BUTTON = "<<< begin";
	private static final int GOMOKU_TABLE_DIMENSION = 15;
	private static final String[] SYMBOLS = {"", "X", "O"};
	private static final int GOMOKU_CELL_SIZE = 20;
	private static final int GOMOKU_CELL_BORDER = 2;
	private static final int GOMOKU_PLAY_DELAY = 800;
	
	private final List<Integer> turns;
	private int turnNumber;
	
	private final Grid grid;
	private final Button resetButton;
	private final Button backwardButton;
	private final Button playButton;
	private final Button forwardButton;
	private final Button toEndButton;
	
	private Timer playTimer;

	public GomokuVisualizer(List<BattleTurn> moves) {
		this.turns = new ArrayList<Integer>();
		for (BattleTurn m: moves) {
			turns.add(m.getField());
		}
		
		setHorizontalAlignment(ALIGN_CENTER);
		
		grid = new Grid(GOMOKU_TABLE_DIMENSION+1, GOMOKU_TABLE_DIMENSION+1);
		
		this.add(grid);
		
		grid.setBorderWidth(GOMOKU_CELL_BORDER);
		for (int i=0; i<GOMOKU_TABLE_DIMENSION + 1; ++i) {
			for (int j=0; j<GOMOKU_TABLE_DIMENSION + 1; ++j) {
				setSymbol(i-1, j-1, 0);
				grid.getCellFormatter().setWidth(i, j, GOMOKU_CELL_SIZE+"px");
				grid.getCellFormatter().setHeight(i, j, GOMOKU_CELL_SIZE+"px");
				grid.getCellFormatter().setHorizontalAlignment(i, j, ALIGN_CENTER);
				grid.getCellFormatter().setVerticalAlignment(i, j, ALIGN_MIDDLE);
			}
		}
		for (int i=0; i<GOMOKU_TABLE_DIMENSION; ++i) {
			grid.setWidget(0, i+1, new Label(Character.toString((char)('A'+i))));
		}
		for (int i=0; i<GOMOKU_TABLE_DIMENSION; ++i) {
			grid.setWidget(i+1, 0, new Label("" + (i+1)));
		}
		
		HorizontalPanel controls = new HorizontalPanel();
		controls.setWidth("100%");
		controls.setHorizontalAlignment(ALIGN_CENTER);
		this.add(controls);
				
		resetButton = new Button(RESET_BUTTON);
		resetButton.setWidth("100%");
		resetButton.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				showTurn(0);
			}
		});
		controls.add(resetButton);
		
		backwardButton = new Button(BACKWARD_BUTTON);
		backwardButton.setWidth("100%");
		backwardButton.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				showTurn(turnNumber-1);
			}
		});
		controls.add(backwardButton);
		
		playButton = new Button(PLAY_BUTTON);
		playButton.setWidth("100%");
		playButton.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				if (playTimer == null) {
					
					playTimer = new Timer() {
						
						@Override
						public void run() {
							showTurn(turnNumber+1);
						}
					};
					
					startPlaying();
				} else {
					stopPlaying();
				}
			}
		});
		controls.add(playButton);
		
		forwardButton = new Button(FORWARD_BUTTON);
		forwardButton.setWidth("100%");
		forwardButton.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				showTurn(turnNumber+1);
			}
		});
		controls.add(forwardButton);
		
		toEndButton = new Button(TO_END_BUTTON);
		toEndButton.setWidth("100%");
		toEndButton.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				showTurn(turns.size()-1);
			}
		});
		controls.add(toEndButton);
		
		if(moves.size() > 0) {
			showTurn(0);
		} else {
			resetButton.setEnabled(false);
			backwardButton.setEnabled(false);
			playButton.setEnabled(false);
			forwardButton.setEnabled(false);
			toEndButton.setEnabled(false);
		}
	}

	protected void startPlaying() {
		playTimer.scheduleRepeating(GOMOKU_PLAY_DELAY);
		playButton.setHTML(PAUSE_BUTTON);
		resetButton.setEnabled(false);
		backwardButton.setEnabled(false);
		forwardButton.setEnabled(false);
		toEndButton.setEnabled(false);
		playTimer.run();
	}

	protected void showTurn(int i) {
		if (i == 0) {
			resetButton.setEnabled(false);
			backwardButton.setEnabled(false);
			forwardButton.setEnabled(playTimer == null);
			toEndButton.setEnabled(playTimer == null);
			playButton.setEnabled(true);
		} else if (i == turns.size()-1) {
			if (playTimer != null) {
				stopPlaying();
			}
			resetButton.setEnabled(playTimer == null);
			backwardButton.setEnabled(playTimer == null);
			playButton.setEnabled(false);
			forwardButton.setEnabled(false);
			toEndButton.setEnabled(false);
		} else {
			resetButton.setEnabled(playTimer == null);
			backwardButton.setEnabled(playTimer == null);
			forwardButton.setEnabled(playTimer == null);
			toEndButton.setEnabled(playTimer == null);
			playButton.setEnabled(true);
		}
		turnNumber = i;
		
		for (int k=0; k<GOMOKU_TABLE_DIMENSION; ++k) {
			for (int h=0; h<GOMOKU_TABLE_DIMENSION; ++h) {
				setSymbol(k, h, 0);
			}
		}
		for (int j=0; j<=turnNumber; ++j) {
			setSymbol(turns.get(j)/GOMOKU_TABLE_DIMENSION, turns.get(j)%GOMOKU_TABLE_DIMENSION, 1+j%2);
		}
	}

	private void setSymbol(int i, int j, int k) {
		//grid.setText(i, j, SYMBOLS[k]);
		Label symbol = new Label(SYMBOLS[k]);
		if (k == 1) {
			symbol.setStyleName("symbol_cross");
		}
		if (k == 2) {
			symbol.setStyleName("symbol_circle");
		}
		grid.setWidget(i+1, j+1, symbol);
	}
	
	private void stopPlaying() {
		playButton.setHTML(PLAY_BUTTON);
		playTimer.cancel();
		playTimer = null;
		
		resetButton.setEnabled(true);
		backwardButton.setEnabled(true);
		forwardButton.setEnabled(true);
		toEndButton.setEnabled(true);
	}
}
